package lex.dm.loader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import org.lex.io.IO;
import org.lex.utils.text.Splitter;

import lex.dm.utils.DBUtils;

public abstract class AbstractDataLoader {
	private static final String MISSING_VALUES = "?";
	private long loadedRecordCount = 0;
	private final Connection con;
	private final String tableName;

	public AbstractDataLoader(Connection con, String tableName) {
		this.con = con;
		this.tableName = tableName;
	}

	public abstract int getColumnCount();

	public abstract String getCreateTableSQL();

	public long getLoadedRecordCount() {
		return this.loadedRecordCount;
	}

	private void resetCounter() {
		this.loadedRecordCount = 0;
	}

	public String getTableName() {
		return this.tableName;
	}

	/**
	 * used in load(InputStream)
	 * 
	 * @param column
	 * @param value
	 * @return
	 */
	protected String process(int index, String value) {
		return value;
	}

	public void load(InputStream in) throws IOException, SQLException {
		this.prepareTable(this.getCreateTableSQL());
		this.resetCounter();
		int COLUMN_COUNT = this.getColumnCount();
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String line = null;
		StringBuilder buf = new StringBuilder();
		String cmd = "insert into " + tableName + " values (";
		Statement s = con.createStatement();
		s.execute("delete from " + tableName);
		while (true) {
			line = reader.readLine();
			if (null == line) {
				IO.closeQuietly(reader);
				break;
			}
			String[] tokens = Splitter.CommaSplitter.split(line);
			if (COLUMN_COUNT != tokens.length) {
				System.err.println("format error: " + line + " -> " + tokens.length + " tokens");
				continue;
			} else {
				// insert record
				buf.setLength(0);
				buf.append(cmd);
				for (int i = 0; i < tokens.length; i++) {
					if (MISSING_VALUES.equals(tokens[i]))
						tokens[i] = "null";
					else
						tokens[i] = this.process(i, tokens[i]);
					buf.append(tokens[i]);
					if (i < tokens.length - 1)
						buf.append(',');
				}
				buf.append(')');
				s.execute(buf.toString());
				this.stepCounter(1);
			}
		}
	}

	protected void stepCounter(long n) {
		this.loadedRecordCount += n;
	}

	protected void prepareTable( String createTableSQL ) throws SQLException
	{
		for( String s : DBUtils.getTableNames( con, null ) )
			if( s.equalsIgnoreCase( tableName ) )
				return;
		con.createStatement().execute( createTableSQL );
	}
}
